package sapling.logic.algorithm.pcb.dispatcher;

import sapling.logic.algorithm.pcb.queue.Node;
import sapling.logic.algorithm.pcb.queue.PriorityQueue;
import sapling.logic.object.pcb.ProcessControlBlock;
import sapling.main.OSEnvironment;
import sapling.util.ReadConfig;

public class PriorityDispatcher extends Dispatcher {

	public PriorityDispatcher(OSEnvironment env) {
		super(env);
	}

	@Override
	protected boolean switchOver() {

		this.env.getPcbRunning().setLiveLong(this.env.getPcbRunning().getLiveLong()-1);
		this.env.getPcbRunning().setPriority(this.env.getPcbRunning().getPriority()<=1 ? 1 : this.env.getPcbRunning().getPriority()-1);
		this.setPriorities();

		if (this.env.getPcbRunning().getLiveLong() <= 0) {
			this.env.getPcbRunning().release();
			if (this.env.getPcbQueue().isEmpty()) {
				this.env.setPcbRunning(null);
				return true;
			}
			this.env.setPcbRunning(this.env.getPcbQueue().dequeue());
			return false;
		}
		if (!this.env.getPcbQueue().isEmpty() &&
				this.env.getPcbRunning().getPriority() < this.env.getPcbQueue().peek().getPriority()) {
			this.env.getPcbRunning().setPriority(this.env.getPcbRunning().getInitPriority());
			this.env.getPcbQueue().enqueue(this.env.getPcbRunning());
			this.env.setPcbRunning(this.env.getPcbQueue().dequeue());
		}
		return false;
	}

	private void setPriorities() {
		Node<ProcessControlBlock> temp = this.env.getPcbQueue().getHead().getNext();
		while (temp != null) {
			if (temp.getData().getTimes() > ReadConfig.TIME_LIMIT) {
				((PriorityQueue) (this.env.getPcbQueue())).upPriority(temp, 1);
				temp.getData().setTimes(-1);
			}
			temp = temp.getNext();
		}
		temp = this.env.getPcbQueue().getHead().getNext();
		while (temp != null) {
			temp.getData().setTimes(temp.getData().getTimes()+1);
			temp = temp.getNext();
		}
	}
}
